package util.delicious;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Map.Entry;

import org.apache.bcel.classfile.Constant;

import util.io.BinaryInput;
import util.io.BinaryOutput;
import util.nlp.*;

public class ModelGenerator implements Constants {

	/**
	 * @param args
	 */

	public static void startShell(String path) {

		LM model = readModel(path);

		Scanner in = new Scanner(System.in);

		// Reads a single line from the console
		// and stores into name variable

		String word = "";

		HashSet<String> tags = new HashSet<String>();

		while (!word.equals("abort")) {

			System.out.println("Enter list of evidence tags:");
			word = "";
			while (!word.equals("exit") && !word.equals("abort")) {

				System.out.print(">");
				word = in.nextLine();

				if (!word.equals("exit"))
					tags.add(word);

			}

			if (!word.equals("abort") || !word.equals("exit")) {

				LinkedList<Entry<String, Double>> list = model
						.getRankedTags(tags);

				for (int i = 0; i < 30 && i <list.size(); i++) {

					Entry<String, Double> entry = list.get(i);

					
					if(!entry.getKey().equals(Constants.UNI_TOTAL_TAG))
					System.out.println((i + 1) + ": " + entry.getKey() + "\t"
							+ entry.getValue());

				}

			}

		}

		in.close();

	}

	public static void startShellDebugging(String pathData, String external_users,String external_tags,
			int min_freq, int max_freq) {

		LM model = new LM();

		model.generateAspectModel(pathData, external_users, external_tags, min_freq, max_freq);

		Scanner in = new Scanner(System.in);

		// Reads a single line from the console
		// and stores into name variable

		String word = "";

		HashSet<String> tags = new HashSet<String>();

		while (!word.equals("abort")) {

			System.out.println("Enter list of evidence tags:");
			word = "";
			while (!word.equals("exit") && !word.equals("abort")) {

				System.out.print(">");
				word = in.nextLine();

				if (!word.equals("exit"))
					tags.add(word);

			}

			if (!word.equals("abort") || !word.equals("exit")) {

				LinkedList<Entry<String, Double>> list = model
						.getRankedTags(tags);

				for (int i = 0; i < 30; i++) {

					Entry<String, Double> entry = list.get(i);

					System.out.println((i + 1) + ": " + entry.getKey() + "\t"
							+ entry.getValue());

				}

			}

		}

		in.close();

	}

	public static void startShell1(String path) {

		Scanner in = new Scanner(System.in);

		// Reads a single line from the console
		// and stores into name variable

		String word = "";

		HashSet<String> tags = new HashSet<String>();

		while (!word.equals("abort")) {

			System.out.println("Enter list of evidence tags:");
			word = "";
			while (!word.equals("exit") && !word.equals("abort")) {

				System.out.print(">");
				word = in.nextLine();

				if (!word.equals("exit"))
					tags.add(word);

			}

		}

		in.close();
	}

	public static void startShellThreads(String path) {

		Scanner in = new Scanner(System.in);

		// Reads a single line from the console
		// and stores into name variable

		String word = "";

		HashSet<String> tags = new HashSet<String>();

		while (!word.equals("abort")) {

			System.out.println("Enter list of evidence tags:");
			word = "";
			while (!word.equals("exit") && !word.equals("abort")) {

				System.out.print(">");
				word = in.nextLine();

				if (!word.equals("exit"))
					tags.add(word);

			}

		}

		in.close();
	}

	public static void generateModel(String pathData, String users, String tags_all,
			String stopWords, String outputFile, int min_freq, int max_freq) {

		LM model = new LM();

		model.generateAspectModel(pathData, users,tags_all, min_freq, max_freq);

		if (outputFile != null) {

			writeModel(model, outputFile);
			System.out.println("Process finished.");

		}

	}

	public static void writeModel(LM model, String outputFile) {
		// TODO Auto-generated method stub

		BinaryOutput out = new BinaryOutput(outputFile);

		// write graph with conditional probabilities
		writeGraphModel(model.getGraphModel(), out);

		// writeUnigramNumber
		writeUnigramsNumber(out, model.getTotal_unigrams());

		// write tags users hash
		writeHashOfSets(out, model.getUserTags());

		// write users frequency kids
		writeFrequencyHash(out, model.getUsersFreqKids());

		// users frequency total
		writeFrequencyHash(out, model.getUsersFreq());

		// tags frequency total
		writeFrequencyHash(out, model.getTagsFreq());

	}

	/**
	 * Write graph nodes of a model to a binary file with the following format
	 * 
	 * 
	 * 
	 * 
	 * @param model
	 */
	public static void writeGraphModel(Hashtable<String, Hashtable<String, Double>> graph,BinaryOutput out) {

	

		
		Enumeration<String> keys = graph.keys();

		while (keys.hasMoreElements()) {

			String key = keys.nextElement();

			out.writeString(key);
			//out.writeDouble(-1.0);

			Hashtable<String, Double> hash = graph.get(key);

			Enumeration<String> iterator = hash.keys();

			while (iterator.hasMoreElements()) {

				String key2 = iterator.nextElement();
				double value = hash.get(key2);

				// revise
				out.writeString(key2);

				out.writeDouble(value);

				//System.out.println("writing:" + key + "\t" + key2 + "\t"+ value);

			}

			out.writeString(Constants.FINAL_ROW_TAG);
			//out.writeDouble(-1.0);

		}

		// add total number of unigrams

		
		// adding flag to end binary file
		out.writeString(Constants.FINAL_FILE_TAG);

		//out.writeDouble(-1.0d);

	}

	
	/**
	 * Write number of unigrams in the model
	 * 
	 * 
	 * @param size
	 */
	public static void writeUnigramsNumber(BinaryOutput out , Double size){
		
		
		out.writeDouble(size);
				
	}
	
	
	public static void readUnigramsNumber(BinaryInput in, LM model){
		
		
		double size = in.readDouble();
	
		model.setTotal_unigrams(size);
		
		//check this
		
	}
	
	
	
	public static void readGraphModel(BinaryInput in,
			Hashtable<String, Hashtable<String, Double>> graph) {

		String key = "";
		double distance;

		key = in.readString();

		while (!key.equals(Constants.FINAL_FILE_TAG)
				&& !key.equals(Constants.FINAL_HASH_TAG)) {

			Hashtable<String, Double> hash = new Hashtable<String, Double>();

			// First node of the row

			String key2 = in.readString();

			while (!key2.equals(Constants.FINAL_ROW_TAG)) {

				distance = in.readDouble();
				
				
			//	System.out.println("Adding:"  + key  + "\t" + key2 + "\t" + distance);
				hash.put(key2, distance);

				key2 = in.readString();

			}

			graph.put(key, hash);

			key = in.readString();

		}

	}
	
	
	public static LM readModel(String modelFile) {

		LM model = new LM();

		BinaryInput in = new BinaryInput(modelFile);

		// write graph with conditional probabilities
		readGraphModel(in, model.getGraphModel());

		// writeUnigramNumber
		readUnigramsNumber(in, model);

		// write tags users hash
		readHashOfSets(in, model.getUserTags());

		// write users frequency kids
		readFrequencyHash(in, model.getUsersFreqKids());

		// users frequency total
		readFrequencyHash(in, model.getUsersFreq());

		// tags frequency total
		readFrequencyHash(in, model.getTagsFreq());

		return model;

	}

	public static void printGraph(Hashtable<String, ArrayList<Node>> graph) {

		Enumeration<String> keys = graph.keys();

		while (keys.hasMoreElements()) {

			String key = keys.nextElement();

			ArrayList<Node> list = graph.get(key);

			System.out.println(key);
			for (int i = 0; i < list.size(); i++) {

				System.out.println("\t" + list.get(i).getWord() + "\t"
						+ list.get(i).getDistance());

			}

		}

	}
	
	
	public static void  writeUserData(LM model, String path){
		
	Hashtable<String, Double> usersFreq = model.getUsersFreq();
	Hashtable<String, Double> usersFreqKids = model.getUsersFreqKids();
	Hashtable<String, HashSet<String>> userTags = model.getUserTags();
		
	
	/**
	 * Safe in a binary file these info  
	 */
	
	//users Freq
	
	Enumeration<String> keys = usersFreq.keys();
	
	while(keys.hasMoreElements()){
		
		
		
		
	}
	
	
		
	}
	
	public static void writeHashOfSets(BinaryOutput out,
			Hashtable<String, HashSet<String>> hash) {

		Enumeration<String> keys = hash.keys();

		while (keys.hasMoreElements()) {

			String key = keys.nextElement();

			HashSet<String> set = hash.get(key);

			Iterator<String> iter = set.iterator();

			out.writeString(key);
			while (iter.hasNext()) {

				String element = iter.next();

				out.writeString(element);

			}

			out.writeString(Constants.FINAL_ROW_TAG);

		}

		out.writeString(Constants.FINAL_HASH_TAG);

	}
	
	
	public static void readHashOfSets(BinaryInput in,
			Hashtable<String, HashSet<String>> hash) {

		String key = in.readString();

		while (!key.equals(Constants.FINAL_HASH_TAG)
				&& !key.equals(Constants.FINAL_FILE_TAG)

		) {

			HashSet<String> set = new HashSet<String>();

			String element = in.readString();

			while (!element.equals(Constants.FINAL_ROW_TAG)) {
				set.add(element);

				element = in.readString();

			}

			hash.put(key, set);

			key = in.readString();

		}
	}

	public static void writeFrequencyHash(BinaryOutput out,
			Hashtable<String, Double> hash) {

		Enumeration<String> keys = hash.keys();

		
		double total=0;
		while (keys.hasMoreElements()) {

			String key = keys.nextElement();

			out.writeString(key);
			out.writeDouble(hash.get(key));
			
			total = total + hash.get(key);

		}

		out.writeString(Constants.UNI_TOTAL_TAG);
		out.writeDouble(total);
		
		out.writeString(Constants.FINAL_HASH_TAG);

	}

	public static void readFrequencyHash(BinaryInput in,
			Hashtable<String, Double> hash) {

		String key = in.readString();

		while (!key.equals(Constants.FINAL_HASH_TAG)
				&& !key.equals(Constants.FINAL_FILE_TAG)) {

			hash.put(key, in.readDouble());

			key = in.readString();

		}

	}
	
	
	public static void testModel(String path) {

		LM model = readModel(path);

		// test uni variables

		// total unigrams

		// graph

		System.out.println(model.getGraphModel().size());

		// users Global

		System.out.println(model.getUsersFreq().size());

		Enumeration<String> keys = model.getUsersFreq().keys();

		while (keys.hasMoreElements()) {
			String key = keys.nextElement();
			System.out.println(key + "\t" + model.getUsersFreq().get(key));
		}

		System.out.println(model.getUsersFreqKids().size());

		keys = model.getUsersFreqKids().keys();

		while (keys.hasMoreElements()) {
			String key = keys.nextElement();
			System.out.println(key + "\t" + model.getUsersFreqKids().get(key));
		}

		System.out.println(model.getTagsFreq().size());

		keys = model.getTagsFreq().keys();
		
		

		while (keys.hasMoreElements()) {
			String key = keys.nextElement();

			System.out.println(key + "\t" + model.getTagsFreq().get(key));
		}
		
		
		
		System.out.println(model.getUserTags().size());
		

		keys = model.getUserTags().keys();
		
		

		while (keys.hasMoreElements()) {
			String key = keys.nextElement();

			
			HashSet<String> set = model.getUserTags().get(key);
			
			Iterator<String> iter2 = set.iterator();
			while(iter2.hasNext()){
				
				
				System.out.println(key + "--\t" + iter2.next());
			}
					
		
		}
		
		

		System.out.println(model.getTotal_unigrams() + "\t"
				+ model.getTotal_items_global());

	}
	
	

	public static void modelGeneratorScript() {

		String pathSuffix = "/home/sergio/Dropbox/data/delicious/";

		
		
		/**
		 * DElicious kids collection
		 * 
		 */
		String path = pathSuffix+ "delicious_kids_final_thesaurus.txt";
		path = pathSuffix + "delicious_filtered_normalized.txt";

		
		/**
		 * Global frequency counts (tags and users)
		 * 
		 * 
		 */
		
		String usersAll = pathSuffix + "delicious_users.freq.txt";
		String tagsAll = pathSuffix + "tags_all_unigrams.txt";

		
		
		/**
		 * 
		 * Path of output model
		 * 
		 */
		
		String output = pathSuffix + "model_filtered_K4_normalized.bin";

		
		/**
		 * method invocation
		 * 
		 * 
		 */
		
		generateModel(path, usersAll, tagsAll, null, output, 0,	Integer.MAX_VALUE);

	}
	
	public static void main(String[] args) {

		// TODO Auto-generated method stub

		// generateModel(path,null);

		String pathSuffix = "/home/sergio/Dropbox/data/delicious/";

		String path = pathSuffix + "delicious_kids_final_thesaurus_filtered.txt";
		path = pathSuffix + "delicious_filtered_normalized.txt";
		
		
		
		//
		String usersAll = pathSuffix + "delicious_users.freq.txt";
		String tagsAll = pathSuffix + "tags_all_unigrams.txt";
		
		String output = pathSuffix + "model_normalized.bin";
		
	
		
		modelGeneratorScript();
		
	

	//	generateModel(path, usersAll,tagsAll, null, output, 0, Integer.MAX_VALUE);
		
		//testModel(output);
		
		// startShellDebugging(path, usersAll, 10, Integer.MAX_VALUE);
		// startShell(output);

	}

}
